Skip to content

Vue 2:生命周期、$nextTick、computed 与 watch

按「何时执行钩子」「何时 DOM 可用」「computed 与 watch 如何取舍」三条线展开。


一、生命周期阶段

各阶段含义

钩子说明
beforeCreate实例创建完成前,data / el 等尚未初始化
created实例创建完成,datamethods 等已就绪,模板尚未挂载
beforeMount挂载前:已编译模板、生成 VNode,真实 DOM 尚未挂载,$el 常为不可用状态
mounted挂载完成:VNode 已 patch 到真实 DOM,$el 可用
beforeUpdate数据已变,DOM 尚未更新
updatedDOM 已随数据更新完毕(勿在 updated 里无脑改数据,易死循环)
beforeDestroy销毁前,适合做清理(定时器、监听、全局事件)
destroyed销毁完成,子组件也已销毁

keep-alive 专属

  • activated:缓存组件被激活(回到前台)。
  • deactivated:缓存组件被停用(退到后台)。

errorCaptured

可捕获子孙组件错误,用于兜底 UI 或日志(与全局 errorHandler 配合)。


二、执行顺序(洋葱模型)

  1. 首次挂载:父 beforeCreate → 父 created → 父 beforeMount → 子 beforeCreate → … → 子 mountedmounted
  2. 更新:父 beforeUpdate → 子 beforeUpdate → 子 updated → 父 updated
  3. 销毁:父 beforeDestroy → 子 beforeDestroy → 子 destroyed → 父 destroyed

三、常见实践问题

何时操作 DOM?

mountedupdated 中获取 DOM 更稳妥;若需保证整棵子树已更新,结合 this.$nextTick

何时发 Ajax?

createdmounted 均可;created 更早(不等 DOM)。若依赖 DOM 尺寸再请求,选 mounted

Vue 2 与 Vue 3 钩子对照(简述)

  • Vue 3 用 setup(执行时机在 beforeCreate ~ created 之间)承接创建阶段逻辑。
  • 其余钩子多为 onXxx 函数形式。

四、v-if="false" 与渲染

v-if="false" 的模板在初始化时不会渲染,编译阶段即跳过,不会产生对应 VNode/DOM;与 nextTick 无「强行渲染」关系。


五、$nextTick

Vue 如何更新 DOM?

数据变化后,Vue 异步批量刷新视图,合并同一轮事件循环里的多次修改,减少重复渲染。

$nextTick 作用

DOM 更新完成后执行回调,用于读取布局(offsetHeightscrollTop 等)或依赖最新 DOM 的逻辑。

典型场景

修改数据后立刻测量 DOM、聚焦输入框、初始化依赖 DOM 的第三方库等。


六、computed 与 watch

一句话区分

  • computed:依赖多个响应式数据,返回一个派生值有缓存;适合「由 A、B 算出 C」;不适合把重副作用、异步逻辑塞进去。
  • watch:监听一个或多个数据源,变化时执行自定义逻辑无缓存;适合异步请求、日志、联动其它状态。

选用建议

  • 推导展示数据computed
  • 数据变化触发副作用(尤其异步)watch
  • 避免用 watch 去做 computed 能表达的纯计算,以免冗余。

七、注意事项汇总

  1. 不要在 updated 中无条件修改响应式数据,容易无限循环。
  2. mounted 不保证所有子组件都已挂载完毕;需「全家就绪」时用 $nextTick 或业务上的就绪标志。
  3. beforeCreate 中勿依赖未初始化的实例字段(早期访问 this 上尚未就绪的内容需谨慎)。
  4. 销毁清理优先放在 beforeDestroydestroyed 里实例尚可访问但绑定已失效,不宜作为主清理点。
  5. keep-alive 缓存的组件不会走 destroyed,而走 deactivated

下一章:响应式原理·data·丢失响应式与 props